import numpy as np
import pandas as pd
from keras import callbacks
from keras.models import load_model
import keras
from keras import backend as K
import keras.optimizers as opt
from keras import Input,layers
from keras.models import Model
from keras import regularizers
import process_data_auto as process_data
import bayes_opt
import run_test_auto
callback_list = [

        callbacks.ModelCheckpoint(filepath="model_1.h5", monitor="val_loss", save_best_only=True),
        callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.8, verbose=1, patience=1)
    ]


def tversky_loss(y_true, y_pred):
    # 这俩参数能调，aplha是多惩罚假阳性，beta是多惩罚假阴性

    alpha = 0.92

    beta = 1 - alpha

    ones = K.ones(K.shape(y_true))

    p0 = y_pred  # proba that voxels are class i

    p1 = ones - y_pred  # proba that voxels are not class i

    g0 = y_true

    g1 = ones - y_true

    num = K.sum(p0 * g0)

    den = num + alpha * K.sum(p0 * g1) + beta * K.sum(p1 * g0)

    T = K.sum(num / den)  # when summing over classes, T has dynamic range [0 Ncl]

    Ncl = K.cast(K.shape(y_true)[-1], 'float32')

    return Ncl - T
def getData():
    data = np.array(pd.read_csv("data_1.csv", names=['prov_id', 'area_id', 'chnl_type', 'service_type', 'product_type',
                                                     'innet_months', 'total_times', 'total_flux', 'total_fee',
                                                     'pay_fee', 'sex', 'age', 'manu_name', 'term_type', 'max_rat_flag',
                                                     'is_5g_base_cover', 'is_work_5g_cover', 'is_home_5g_cover',
                                                     'is_work_5g_cover_l01', 'is_home_5g_cover_l01',
                                                     'is_work_5g_cover_l02', 'is_home_5g_cover_l02', 'activity_type',
                                                     'is_act_expire', 'comp_type', 'call_days', 're_call10',
                                                     'short_call10', 'long_call10', 'bank_cnt', 'game_app_flux',
                                                     'live_app_flux', 'video_app_flux', 'city_5g_ratio', 'city_level',
                                                     'app_sum']))
    label = np.array(pd.read_csv("label_1.csv"))
    data = data[1:, :]

    data_test = np.array(pd.read_csv("data_test_1.csv",
                                     names=['prov_id', 'area_id', 'chnl_type', 'service_type', 'product_type',
                                            'innet_months', 'total_times', 'total_flux', 'total_fee', 'pay_fee', 'sex',
                                            'age', 'manu_name', 'term_type', 'max_rat_flag', 'is_5g_base_cover',
                                            'is_work_5g_cover', 'is_home_5g_cover', 'is_work_5g_cover_l01',
                                            'is_home_5g_cover_l01', 'is_work_5g_cover_l02', 'is_home_5g_cover_l02',
                                            'activity_type', 'is_act_expire', 'comp_type', 'call_days', 're_call10',
                                            'short_call10', 'long_call10', 'bank_cnt', 'game_app_flux', 'live_app_flux',
                                            'video_app_flux', 'city_5g_ratio', 'city_level', 'app_sum']))
    label_test = np.array(pd.read_csv("label_test_1.csv"))
    data_test = data_test[1:, :]

    return data,label,data_test,label_test

def precision(y_true, y_pred):
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
    return true_positives / (predicted_positives + K.epsilon())

def recall(y_true, y_pred):
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
    return true_positives / (possible_positives + K.epsilon())
def f1(y_true, y_pred):
    def precision(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
        precision = true_positives / (predicted_positives + K.epsilon())
        return precision
    def recall(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
        recall = true_positives / (possible_positives + K.epsilon())
        return recall
    precision = precision(y_true, y_pred)
    recall = recall(y_true, y_pred)
    return 2 * ((precision * recall) / (precision + recall + K.epsilon()))
def getNet():

    data_input = Input(shape=(36,))

    x = layers.Dense(256, activation="relu")(data_input)
    x = layers.Dropout(0.3)(x)
    x = layers.normalization.BatchNormalization()(x)



    y = layers.Dense(256, activation="relu")(x)
    y = layers.Dropout(0.3)(y)
    y = layers.normalization.BatchNormalization()(y)
    y = layers.Dense(256, activation="relu")(y)
    y = layers.Dropout(0.3)(y)
    y = layers.normalization.BatchNormalization()(y)
    y = layers.Dense(256, activation="relu")(y)
    y = layers.Dropout(0.3)(y)
    y = layers.normalization.BatchNormalization()(y)



    z = layers.Dense(256, activation="relu")(x)
    z = layers.Dropout(0.3)(z)
    z = layers.normalization.BatchNormalization()(z)
    z = layers.Dense(256, activation="relu")(z)
    z = layers.Dropout(0.3)(z)
    z = layers.normalization.BatchNormalization()(z)
    z = layers.Dense(256, activation="relu")(z)
    z = layers.Dropout(0.3)(z)
    z = layers.normalization.BatchNormalization()(z)



    xr = layers.Dense(256, activation="relu")(x)
    xr = layers.Dropout(0.3)(xr)
    xr = layers.normalization.BatchNormalization()(xr)
    xr = layers.Dense(256, activation="relu")(xr)
    xr = layers.Dropout(0.3)(xr)
    xr = layers.normalization.BatchNormalization()(xr)
    xr = layers.Dense(256, activation="relu")(xr)
    xr = layers.Dropout(0.3)(xr)
    xr = layers.normalization.BatchNormalization()(xr)

    x = layers.concatenate([y, z, xr])

    x = layers.Dense(256, activation="relu")(x)
    x = layers.Dropout(0.2)(x)

    x = layers.Dense(32, activation="relu")(x)
    x = layers.Dropout(0.2)(x)
    x = layers.Dense(1, activation="sigmoid")(x)

    model_1 = Model(inputs=data_input, outputs=x)
    model_1.compile(optimizer=opt.adam(), loss=tversky_loss, metrics=[f1, recall, precision])

    return model_1

for num in range(90,91):
    model_1=getNet()
    process_data.genData(process_data.posNum*5)
    data,label,data_test,label_test=getData()
    model_1.fit(data,label, epochs=20, batch_size=4096, callbacks=callback_list,validation_data=(data_test,label_test))
    #model_1.save("model_1.h5")
    run_test_auto.save_csv(num)
    print([num]*20)



